import time
from fastapi import FastAPI, Request, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
import asyncio
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse

from bot_api_v1.app.middlewares.logging_middleware import log_middleware
from bot_api_v1.app.middlewares.request_counter import add_request_counter
from bot_api_v1.app.core.logger import logger,db_log_sink
from bot_api_v1.app.core.exceptions import http_exception_handler, CustomException
from bot_api_v1.app.api.main import router as api_router
from bot_api_v1.app.tasks.base import wait_for_tasks, wait_for_log_tasks, TASK_TYPE_LOG
from bot_api_v1.app.db.init_db import init_db, wait_for_db
from bot_api_v1.app.core.config import settings
from bot_api_v1.app.middlewares.rate_limit import RateLimitMiddleware
from bot_api_v1.app.middlewares.enhanced_rate_limit import EnhancedRateLimitMiddleware
from bot_api_v1.app.middlewares.referer_check import RefererCheckMiddleware
from bot_api_v1.app.middlewares.user_agent_filter import UserAgentFilterMiddleware
from bot_api_v1.app.api.routers import media,ticket,wechat_mp,script,wechat,test_api,monitoring
from bot_api_v1.app.services.business.config_service import ConfigService

# from bot_api_v1.app.monitoring import setup_metrics, metrics_middleware, start_system_metrics_collector
from bot_api_v1.app.services.business.wechat_service import WechatService  # 添加这行导入
import os

# 挂载静态文件目录

# 找到项目根目录（假设是包含src的目录）
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../.."))
static_directory = os.path.join(project_root, "src", "bot_api_v1", "app", "static")


def create_app():
    """创建并配置FastAPI应用"""
    app = FastAPI(
        title=settings.PROJECT_NAME,
        description="高性能API服务",
        version=settings.VERSION,
        docs_url="/docs",  # Swagger UI 路径
        redoc_url="/redoc",  # ReDoc 路径
        openapi_url="/openapi.json",  # OpenAPI JSON文档路径
    )

    # 1. 添加日志中间件
    app.middleware("http")(log_middleware)

    # 2. 添加CORS中间件
    add_cros_middleware(app)

    # # 3. 添加主机验证中间件
    # if settings.ENVIRONMENT == "production":
    #     app.add_middleware(
    #         TrustedHostMiddleware, 
    #         allowed_hosts=settings.ALLOWED_HOSTS
    #     )

    # 4. 添加增强的速率限制中间件
    if settings.ENVIRONMENT == "production":
        app.add_middleware(EnhancedRateLimitMiddleware)
    elif settings.ENVIRONMENT == "development":
        # 在开发环境中也启用增强限流，但使用更宽松的限制
        app.add_middleware(EnhancedRateLimitMiddleware)

    # 5. 添加Referer检查中间件（在限流中间件之后）
    app.add_middleware(RefererCheckMiddleware)

    # 6. 添加User-Agent过滤中间件
    app.add_middleware(UserAgentFilterMiddleware)



    # 7. 添加请求计数中间件
    # add_request_counter(app)
    
    # # 7. 添加Prometheus指标中间件
    # metrics_middleware(app)



    # 注册路由
    app.include_router(api_router, prefix=settings.API_PREFIX)
    app.include_router(script.router, prefix="/script")
    app.include_router(wechat.router, prefix="/wechat")
    app.include_router(wechat_mp.router, prefix="/wechat_mp")
    app.include_router(media.router, prefix="/media")
    app.include_router(ticket.router, prefix="/tkt")
    app.include_router(test_api.router, prefix="/tt")
    app.include_router(monitoring.router, prefix="/monitoring")



    logger.info(f"项目根目录: {project_root}")
    logger.info(f"尝试挂载静态文件目录: {static_directory}")

    # 确保目录存在再挂载
    if os.path.exists(static_directory):
        app.mount("/static", StaticFiles(directory=static_directory), name="static")
    else:
        logger.error(f"静态文件目录不存在: {static_directory}")


    # 注册异常处理器
    app.add_exception_handler(Exception, http_exception_handler)
    
    # 初始化Prometheus指标
    # setup_metrics(app, app_name=settings.PROJECT_NAME)
    
    # # 启动系统指标收集
    # start_system_metrics_collector(app)

    # 添加启动事件处理器
    @app.on_event("startup")
    async def startup_event():
        try:
            # 记录应用启动时间
            app.state.startup_time = time.time()
            
            # 初始化请求计数器
            app.state.request_counts = {
                "total": 0,
                "success": 0,
                "error": 0,
                "by_endpoint": {},
                "by_method": {}
            }
            
            

            # 等待数据库可用
            if not await wait_for_db(
                max_retries=settings.DB_CONNECT_RETRIES,
                interval=settings.DB_CONNECT_RETRY_INTERVAL
            ):
                logger.error("Cannot connect to database, application may not function properly")
            

            # 初始化微信服务实例
            # app.state.wechat_service = WechatService()
            # if settings.CURRENT_WECHAT_MP_MENU_VERSION < settings.TARGET_WECHAT_MP_MENU_VERSION:
            #     try:
            #         access_token = await app.state.wechat_service._get_mp_access_token()
            #         await app.state.wechat_service.create_wechat_menu(access_token)
                    
            #         # 直接更新设置值
            #         settings.CURRENT_WECHAT_MP_MENU_VERSION = settings.TARGET_WECHAT_MP_MENU_VERSION
                    
            #         logger.info_to_db(f"成功创建微信公众号菜单,微信菜单已更新到版本 {settings.TARGET_WECHAT_MP_MENU_VERSION}")
            #     except Exception as e:
            #         logger.error(f"更新微信菜单失败: {str(e)}")

            # 初始化数据库
            # await init_db()
            
            # 仅在开发环境中创建测试数据
            # if settings.ENVIRONMENT == "development" and settings.CREATE_TEST_DATA:
            #     await create_test_data()

            await ConfigService.load_all_to_cache()

            loop = asyncio.get_running_loop()
            db_log_sink.start(loop) # 启动消费者
                
            logger.info(f"Application startup completed in {settings.ENVIRONMENT} environment")
        except Exception as e:
            logger.error(f"Error during startup: {str(e)}", exc_info=True)
            # 在严重错误时，可能需要终止应用
            if settings.ENVIRONMENT == "production":
                logger.critical("Critical startup error in production, exiting")
                import sys
                sys.exit(1)

    # 添加关闭事件处理器
    @app.on_event("shutdown")
    async def shutdown_event():
        logger.info("Application shutdown initiated")
        
        try:
            # 首先等待日志任务完成 - 使用较短的超时时间
            logger.info("Waiting for log tasks to complete...")
            await wait_for_log_tasks(timeout=5)  # 日志任务等待5秒
            
            # 然后等待其他所有任务完成 - 可以使用较长的超时时间
            logger.info("Waiting for all remaining tasks to complete...")
            await wait_for_tasks(timeout=30)  # 其他任务等待30秒
            
            await db_log_sink.stop() # 优雅停止
            logger.info("All tasks completed successfully")
        except Exception as e:
            logger.error(f"Error during task shutdown: {str(e)}", exc_info=True)
        
        logger.info("Application shutdown completed")

    @app.get("/MP_verify_1l7AmoJtFSD4Ftcx.txt")
    async def serve_mp_verify_file():
        file_path = os.path.join(os.path.dirname(__file__), "../MP_verify_1l7AmoJtFSD4Ftcx.txt")
        return FileResponse(file_path, media_type="text/plain")
    
    @app.get("/robots.txt")
    async def serve_robots_txt():
        static_dir = os.path.join(os.path.dirname(__file__), "../static")
        file_path = os.path.join(static_dir, "robots.txt")
        return FileResponse(file_path, media_type="text/plain")
    
    @app.get("/sitemap.xml")
    async def serve_sitemap_xml():
        static_dir = os.path.join(os.path.dirname(__file__), "../static")
        file_path = os.path.join(static_dir, "sitemap.xml")
        return FileResponse(file_path, media_type="application/xml")
    
    @app.get("/baidu_verify_codeva-RAJkBsaLt5.html")
    async def serve_baidu_verify_file():
        static_dir = os.path.join(os.path.dirname(__file__), "../static")
        file_path = os.path.join(static_dir, "baidu_verify_codeva-RAJkBsaLt5.html")
        return FileResponse(file_path, media_type="text/html")
    
    return app



def add_cros_middleware(app: FastAPI):
    # allow_origins 的严格性：

    # 避免使用 "*"：除非你的 API 是完全公开且不需要凭据的，否则在生产中应避免 allow_origins=["*"]。
    # 动态源：如果你的插件可能从多个动态子域名或客户特定的域名加载，你可能需要更复杂的逻辑来验证 Origin 头部，或者在部署时配置一个详尽的列表。
    # allow_credentials=True：

    # 只有当你的前端确实需要发送凭据（例如 cookies、HTTP认证信息、客户端SSL证书）并且服务器需要处理它们时，才应设置为 True。
    # 重要：如果 allow_credentials=True，那么 allow_origins 绝不能是 "*"。必须是具体的域名列表。浏览器会拒绝这种不安全的组合。
    # allow_methods：

    # 避免使用 ["*"]：在生产环境中，最佳实践是明确列出你的 API 端点实际支持和需要暴露给跨域请求的 HTTP 方法，例如：allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]。遵循最小权限原则，只允许必要的方法。
    # allow_headers：

    # 避免使用 ["*"]：与 allow_methods 类似，明确列出前端在请求中会发送的、并且服务器需要接受的自定义请求头，例如：allow_headers=["Content-Type", "Authorization", "X-Requested-With", "X-CSRF-Token"]。如果你的前端不发送自定义头部，那么可能只需要 ["Content-Type"]。


    allowed_origins_production = [
        settings.WECHAT_MP_FRONTEND_URL,
        settings.WECHAT_MINI_FRONTEND_URL,
        settings.COZE_FRONTEND_API_URL,
        settings.FEISHU_SHEET_FRONTEND_API_URL,
        settings.FEISHU_SIDE_FRONTEND_API_URL,
    ]

    allowed_origins_production = [
        "*"
    ]

    allowed_origins_development = [
        "http://localhost:5173", # Vite 默认端口
        "http://localhost:8080", # 
        "http://localhost:3000", # Create React App 默认端口
    ]

    allowed_headers = [
        "Content-Type",
        "Authorization",
        "x-root-trace-key",
        'x-source',
        "x-app-id",
        "x-user-uuid",
        "x-user-nickname",
        "x-base-signature",
        "x-base-id",
        "x-log-id",
        "x-table-id",
        "x-pack-id",
        "x-tenant-key",
        "x-time-zone",
        "x-base-owner-id",
    ]

    current_env = settings.ENVIRONMENT
    origins_to_use = allowed_origins_production if current_env == "production" else allowed_origins_development

    app.add_middleware(
        CORSMiddleware,
        allow_origins= origins_to_use,
        # allow_credentials=True,  # 仅当确实需要且理解其含义时开启
        allow_methods= ["GET", "POST", "PUT", "OPTIONS"], # 列出你的 API 实际使用的方法
        allow_headers= allowed_headers, # 列出实际使用的请求头
        # allow_headers=["*"]
        # expose_headers=["X-Custom-Response-Header-If-Any"], # 如果前端需要读取自定义的响应头
        max_age=600 # 预检请求的缓存时间 (秒)
    )

    